package com.yanqu.road.server.manager.activity.seacraftsouthsea;

import com.yanqu.road.entity.activity.CrossActivityDetail;
import com.yanqu.road.entity.activity.seacraft.*;
import com.yanqu.road.entity.activity.seacraft.config.SeacraftSouthSeaActivityConfig;
import com.yanqu.road.entity.activity.seacraft.config.SeacraftSouthSeaShipConfig;
import com.yanqu.road.entity.battle.IBattleObjectInfo;
import com.yanqu.road.entity.config.battle.BattleResult;
import com.yanqu.road.entity.config.battle.PatronsBattleDetail;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.log.LogSeacraftSouthSeaAttack;
import com.yanqu.road.entity.log.LogSeacraftSouthSeaAttackDetail;
import com.yanqu.road.entity.log.LogSeacraftSouthSeaDurable;
import com.yanqu.road.entity.log.LogSeacraftSouthSeaShip;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.pb.BattlePb;
import com.yanqu.road.pb.activity.SeacraftSouthSeaProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.ActivityMgr;
import com.yanqu.road.server.manager.config.GoodsMgr;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manger.BattleMgr;
import com.yanqu.road.server.manger.TempGoodsBagMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Description 海上争霸 南海丝路
 * @Author cwq
 * @Data 2022/1/20 16:53
 */
public class SeacraftSouthSeaUnionInfo {

    /**
     * 联盟信息
     */
    private SeacraftSouthSeaCrossUnionData unionData;

    /**
     * 船只信息 晋级第一轮 才有数据
     */
    private SeacraftSouthSeaCrossUnionShipData shipData;

    /**
     * 联盟成员
     */
    private Map<Long, SeacraftSouthSeaCrossUserInfo> memberMap = new ConcurrentHashMap<>();

    /**
     * 攻击 细节信息 k:联盟id  v 该联盟的攻击信息
     */
    private Map<String, SeacraftSouthSeaBattleDetailData> attackBattleMap = new ConcurrentHashMap<>();

    /**
     * 防守 细节信息 k:联盟id  v 该联盟的攻击信息
     */
    private Map<String, SeacraftSouthSeaBattleDetailData> defendBattleMap = new ConcurrentHashMap<>();

    /**
     * 攻击日志
     */
    private List<SeacraftSouthSeaCrossRecordData> attackRecordList = new CopyOnWriteArrayList<>();

    /**
     * 防守日志
     */
    private List<SeacraftSouthSeaCrossRecordData> defendRecordList = new CopyOnWriteArrayList<>();

    /**
     * 当前行驶的距离 不入库  排序的时候会用到
     */
    public long distance;

    public SeacraftSouthSeaUnionInfo(SeacraftSouthSeaCrossUnionData unionData) {
        this.unionData = unionData;
    }

    public SeacraftSouthSeaCrossUnionData getUnionData() {
        return unionData;
    }

    public SeacraftSouthSeaCrossUnionShipData getShipData() {
        return shipData;
    }

    public Map<Long, SeacraftSouthSeaCrossUserInfo> getMemberMap() {
        return memberMap;
    }

    public List<SeacraftSouthSeaCrossRecordData> getAttackRecordList() {
        return attackRecordList;
    }

    public List<SeacraftSouthSeaCrossRecordData> getDefendRecordList() {
        return defendRecordList;
    }

    public Map<String, SeacraftSouthSeaBattleDetailData> getAttackBattleMap() {
        return attackBattleMap;
    }

    public Map<String, SeacraftSouthSeaBattleDetailData> getDefendBattleMap() {
        return defendBattleMap;
    }

    /**
     * 初始化船只 （锁定船只属性）
     */
    public synchronized void initShip() {
        if (shipData != null || unionData.getRound() == 0 || !isSynUnionInfo()) {
            return;
        }
        long startTime = SeacraftSouthSeaMgr.getRoundStartTime(unionData.getActivityId(), unionData.getRound());
        long now = DateHelper.getCurrentTime();
        if (now < startTime) {
            return;
        }
        if (shipData == null) {
            shipData = new SeacraftSouthSeaCrossUnionShipData();
            shipData.setActivityId(unionData.getActivityId());
            shipData.setUnionId(unionData.getUnionId());
            shipData.setInsertOption();
            // 初始化耐久度
            if (memberMap.keySet().size() == 0) {
                SeacraftSouthSeaMgr.getLogger().info("海上争霸 南海丝路 初始化船只数据有问题。activityId:{},unionId:{},memberMap.keySet().size():{}", unionData.getActivityId(), unionData.getUnionId(), memberMap.keySet().size());
            }
            unionData.getMemberSet().addAll(memberMap.keySet());
            unionData.setUpdateOption();
        }
    }

    /**
     * 计算船只耐久
     *
     * @return
     */
    public long calDurable() {
        long memberNum = unionData.getMemberSet().size();
        SeacraftSouthSeaShipConfig shipConfig = SeacraftSouthSeaMgr.getShipConfig(this);
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());
        long durable = (activityConfig.shipFirstList.get(0) + shipConfig.getHealth()) * memberNum;
        if (durable <= 0) {
            SeacraftSouthSeaMgr.getLogger().error("海上争霸 计算船只耐久 数据异常，activityId:{},activityConfig.shipFirstList.get(0):{},memberNum:{},shipConfig.getHealth():{},durable:{}", unionData.getActivityId(), activityConfig.shipFirstList.get(0), memberNum, shipConfig.getHealth(), durable);
            durable = 1;
        }
        return durable;
    }

    /**
     * 是否同步过数据
     *
     * @return
     */
    public boolean isSynUnionInfo() {
        return unionData.getUnionBaseInfo() != null && unionData.getUnionBaseInfo().getMasterUserId() != 0;
    }


    /**
     * 重置船只
     */
    public synchronized void resetShip(long refreshTime) {
        if (shipData != null && refreshTime > shipData.getRefreshTime()) {
            long totalDurable = calDurable();
            shipData.setTotalDurable(totalDurable);
            shipData.setRemainDurable(totalDurable);
            shipData.setDistance(0);
            shipData.setEndTime(0);
            shipData.setRefreshTime(refreshTime);
            shipData.getSpeedRecordList().clear();
            shipData.setFixRefreshTime(refreshTime);
            // 清除日志
            attackRecordList.clear();
            defendRecordList.clear();
            attackBattleMap.clear();
            defendBattleMap.clear();
            unionData.getFixDurableMap().clear();
            unionData.setUpdateOption();

            for (SeacraftSouthSeaCrossUserInfo member : memberMap.values()) {
                member.getBaseData().getUseSpeedUpInfoMap().clear();
                member.getBaseData().setUpdateOption();
            }

            // 耐久日志
            int speed = getShipSpeed();
//            SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaDurable(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 1, 0, "", 0, 0, totalDurable, speed, refreshTime));
            CrossAutoLogMgr.add(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 1, 0, "", 0, 0, totalDurable, speed, refreshTime));
        }
    }

    /**
     * 加贡献
     *
     * @param type
     * @param num
     */
    public void addDonationShip(int type, long num, long now) {
        SeacraftSouthSeaShipConfig oldConfig = SeacraftSouthSeaMgr.getShipConfig(this);
        synchronized (unionData) {
            long newValue = Math.max(unionData.getDonationShipMap().getOrDefault(type, 0L) + num, 0);
            unionData.getDonationShipMap().put(type, newValue);
            unionData.setUpdateOption();
        }
        SeacraftSouthSeaShipConfig newConfig = SeacraftSouthSeaMgr.getShipConfig(this);
        // 加升级日志
        if (oldConfig.getLevel() != newConfig.getLevel()) {
            // 等级不一样
//            SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaShip(new LogSeacraftSouthSeaShip(unionData.getActivityId(), unionData.getUnionId(), oldConfig.getLevel(), newConfig.getLevel(), new HashMap<>(unionData.getDonationShipMap()), now));
            CrossAutoLogMgr.add(new LogSeacraftSouthSeaShip(unionData.getActivityId(), unionData.getUnionId(), oldConfig.getLevel(), newConfig.getLevel(), new HashMap<>(unionData.getDonationShipMap()), now));
        }
    }

    /**
     * 刷新船只的航行
     *
     * @param now ms
     * @return 是否抵达
     */
    public boolean refreshShip(SeacraftSouthSeaActivity southSeaActivity, long now) {
        if (shipData == null || shipData.getEndTime() > 0) {
            // 已经抵达终点
            return false;
        }
        // 活动开始时间
        CrossActivityDetail crossActivityDetail = ActivityMgr.getCrossActivityDetail(unionData.getActivityId(), southSeaActivity.getGroupId(), true);
        if (crossActivityDetail.getParam1() <= 0) {
            return false;
        }
        int round = (int) (crossActivityDetail.getParam1());
        if (unionData.getRound() != round) {
            // 该联盟未晋级到该轮
            return false;
        }
        long roundStartTime = SeacraftSouthSeaMgr.getRoundStartTime(unionData.getActivityId(), round);
        if (now < roundStartTime) {
            // 比赛还未开始
            return false;
        }
        if (shipData.getRefreshTime() < roundStartTime) {
            // 加个保护
            resetShip(roundStartTime);
        }
        // 活动开始时间
        long roundEndTime = SeacraftSouthSeaMgr.getRoundEndTime(unionData.getActivityId(), round);
        if (shipData.getRefreshTime() >= roundEndTime) {
            // 比赛结束
            return false;
        }
        // 计算各个加速节点的位移
        List<SeacraftSouthSeaCurSpeedInfo> removeList = new ArrayList<>();
        for (SeacraftSouthSeaCurSpeedInfo item : shipData.getSpeedRecordList()) {
            long speedEndTime = item.getEndT() * DateHelper.SECOND_MILLIONS;
            if (speedEndTime < now) {
                updateShipDistance(southSeaActivity, speedEndTime, roundEndTime);
                removeList.add(item);

            }
        }

        if (!removeList.isEmpty()){
            for (SeacraftSouthSeaCurSpeedInfo item : removeList) {
                shipData.getSpeedRecordList().remove(item);
            }
            shipData.setUpdateOption();
        }

        updateShipDistance(southSeaActivity, now, roundEndTime);
        if (shipData.getEndTime() > 0) {
            shipData.getSpeedRecordList().clear();
        }
        return shipData.getEndTime() > 0;
    }

    /**
     * 更新船只行驶的距离
     *
     * @param southSeaActivity
     * @param updateTime
     * @param roundEndTime
     * @return 返回是否到达终点
     */
    private void updateShipDistance(SeacraftSouthSeaActivity southSeaActivity, long updateTime, long roundEndTime) {
        if (shipData.getEndTime() > 0) {
            return;
        }
        refreshFixShip(updateTime);
        // 当前速度 speed 放大100 倍
        int speed = getShipSpeed(updateTime);
        // 剩余距离
        long totalDistance = southSeaActivity.getRoundDistance();
        long remainDistance = totalDistance - shipData.getDistance();
        // 行驶的时间 ms
        long refreshTime = updateTime;
        if (updateTime > roundEndTime) {
            refreshTime = roundEndTime;
        }
        long diffTime = refreshTime - shipData.getRefreshTime();
        if (diffTime <= 0) {
            return;
        }
        // 行驶的距离 放大一百倍
        long distance = speed * diffTime / (100 * 1000);
        if (distance >= remainDistance) {
            // 到达终点  计算时间到达终点的时间 ms
            long time = remainDistance * 1000 * 100 / speed;
            shipData.setDistance(totalDistance);
            shipData.setRefreshTime(shipData.getRefreshTime() + time);
            shipData.setEndTime(shipData.getRefreshTime());
        } else {
            if (distance > 0 || diffTime > DateHelper.SECOND_MILLIONS) {
                // 加个保护防止太频繁调用接口 防止误差太大
                shipData.setDistance(shipData.getDistance() + distance);
                shipData.setRefreshTime(refreshTime);
            }
        }
        shipData.setUpdateOption();
    }


    /**
     * 到达广播
     */
    public void arrivalBroadcast(SeacraftSouthSeaActivity southSeaActivity) {
        int rank = southSeaActivity.getRankList().indexOf(this) + 1;
        int round = unionData.getRound() + 1;
        unionData.getResultMap().put(round, new SeacraftSouthSeaResultInfo(shipData.getEndTime(), shipData.getDistance(), rank));
        unionData.setUpdateOption();
        // 广播
        southSeaActivity.broadcastArrivalInfo(this, round);
        SeacraftSouthSeaMgr.getLogger().info("海上争霸，南海丝路，船只抵达结果信息，activityId:{},round:{},unionId:{},rank:{},endTime:{}.", unionData.getActivityId(), round, unionData.getUnionId(), rank, shipData.getEndTime());
    }

    /**
     * 获取当前船只速度   放大100 倍
     *
     * @param now ms
     * @return
     */
    private int getShipSpeed(long now) {
        long v = 0;
        if (shipData != null) {
            long durableSpeed = 0;
            SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());
            SeacraftSouthSeaShipConfig shipConfig = SeacraftSouthSeaMgr.getShipConfig(this);
            durableSpeed = activityConfig.shipFirstList.get(1) + shipConfig.getSpeed();
            durableSpeed = durableSpeed * shipData.getRemainDurable() * 100 / shipData.getTotalDurable();
            durableSpeed = Math.max(activityConfig.getSEACRAFT_CRAFT_SPEED_MIN() * 100, durableSpeed);
            // 当前加速的速度
            int addSpeed = 0;
            for (SeacraftSouthSeaCurSpeedInfo item : shipData.getSpeedRecordList()) {
                if (now <= item.getEndT() * DateHelper.SECOND_MILLIONS) {
                    addSpeed += item.getV();
                }
            }
            v = durableSpeed + addSpeed;
        }
        return (int) v;
    }

    private int getShipSpeed() {
        return getShipSpeed(DateHelper.getCurrentTime());
    }

    /**
     * 增加或耐久
     */
    public int addDurable(SeacraftSouthSeaActivity southSeaActivity, int durable) {
        long oldValue = shipData.getRemainDurable();
        long realValue = addDurable(durable);
        // 广播给联盟成员
        broadcastMemberUnionInfo();
        if (oldValue == 0 && shipData.getRemainDurable() > 0) {
            // 从损毁 到 有血的情况 广播给所有
            southSeaActivity.broadcastShipInfoToInActivityUser(this, new ArrayList<>(memberMap.keySet()));
        }
        return (int) realValue;
    }

    /**
     * 加耐久 返回实际加的值
     *
     * @param addValue
     * @return
     */
    private long addDurable(long addValue) {
        long realValue = addValue;
        if (shipData.getRemainDurable() + addValue > shipData.getTotalDurable()) {
            realValue = shipData.getTotalDurable() - shipData.getRemainDurable();
            shipData.setRemainDurable(shipData.getTotalDurable());
        } else {
            shipData.setRemainDurable(shipData.getRemainDurable() + addValue);
        }
        return realValue;
    }


    /**
     * 扣除耐久
     */
    private int deductDurable(SeacraftSouthSeaActivity southSeaActivity, int durable) {
        long oldValue = shipData.getRemainDurable();
        long realValue = deductDurable(durable);
        // 广播给联盟成员
        broadcastMemberUnionInfo();
        if (oldValue > 0 && shipData.getRemainDurable() <= 0) {
            // 损毁 广播给所有
            southSeaActivity.broadcastShipInfoToInActivityUser(this, new ArrayList<>(memberMap.keySet()));
        }
        return (int) realValue;
    }


    /**
     * 扣耐久 返回实际扣的值
     *
     * @param durable
     * @return
     */
    private long deductDurable(long durable) {
        long realValue = durable;
        if (shipData.getRemainDurable() > durable) {
            shipData.setRemainDurable(shipData.getRemainDurable() - durable);
        } else {
            realValue = shipData.getRemainDurable();
            shipData.setRemainDurable(0);
        }
        return realValue;
    }

    /**
     * 广播给联盟成员 当前船只的信息
     */
    public void broadcastMemberUnionInfo() {
        SeacraftSouthSeaProto.BroadcastSeacraftSouthSeaRespMsg.Builder broadcast = SeacraftSouthSeaProto.BroadcastSeacraftSouthSeaRespMsg.newBuilder();
        broadcast.setType(0);
        broadcast.setSeaShipInfo(builderSeacraftSouthSeaShipInfo());
        for (SeacraftSouthSeaCrossUserInfo item : memberMap.values()) {
            MessageHelper.sendPacket(item.getBaseData().getServerId(), item.getBaseData().getUserId(), YanQuMessageUtils.buildMessage(ClientProtocol.U_SEACRAFT_SOUTH_SEA_BROADCAST, broadcast));
        }
    }


    /**
     * 修复船只
     *
     * @param userInfo 联盟成员
     * @param titleId
     */
    @Deprecated
    public int fix(SeacraftSouthSeaActivity activity, SeacraftSouthSeaCrossUserInfo userInfo, int count, int titleId) {
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(userInfo.getBaseData().getActivityId());
        GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(activityConfig.getSEACRAFT_CRAFT_WRENCH_ITEM_ID());
        int damage = (goodsInfo.getParamList().get(0).intValue() + (titleId * goodsInfo.getParamList().get(1).intValue())) * count;
        int score = goodsInfo.getParamList().get(2).intValue() * count / 1000;
        long oldDurable = shipData.getRemainDurable();
        int oldSpeed = getShipSpeed();
        damage = addDurable(activity, damage);

        SeacraftSouthSeaFixDurableInfo fixDurableInfo = unionData.getFixDurableMap().get(userInfo.getBaseData().getUserId());
        if (fixDurableInfo == null) {
            fixDurableInfo = new SeacraftSouthSeaFixDurableInfo();
            unionData.getFixDurableMap().put(userInfo.getBaseData().getUserId(), fixDurableInfo);
        }
        fixDurableInfo.setV(fixDurableInfo.getV() + damage);
        fixDurableInfo.setT(DateHelper.getCurrentSecond());
        unionData.setUpdateOption();
        long time = DateHelper.getCurrentTime();
        addRecord(1, 3, userInfo.getBaseData().getUserId(), "", 0, score, damage, count, time, 0, 0, 0);
        // 日志
//        SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaDurable(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 5, userInfo.getBaseData().getUserId(), userInfo.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), time));
        CrossAutoLogMgr.add(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 5, userInfo.getBaseData().getUserId(), userInfo.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), time));
        if (damage > 0) {
            activity.broadcastSeacraftSouthSeaMarqueeInfo(userInfo.getBaseData().getUserId(), this, this, 3, 0, score, damage, count, time);
        }

        return score;
    }


    /**
     * 使用加速道具 船桨
     *
     * @param activity
     * @param userInfo
     * @param count
     */
    public void useSpeedProp(SeacraftSouthSeaActivity activity, SeacraftSouthSeaCrossUserInfo userInfo, int count, int propId) {
        int now = DateHelper.getCurrentSecond();
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(userInfo.getBaseData().getActivityId());
        String param = activityConfig.getSpeedParam(propId);
        // 加速效果放大一百倍  m/s
        int totalSpeed = 0;
        // 持续时间 s
        int totalContinueTime = 0;
        // 加速路程
        int totalS = 0;
        if (!StringUtils.isNullOrEmpty(param)) {
            List<Integer> paramList = StringUtils.stringToIntegerList(param, ",");
            totalSpeed = paramList.get(0) * count;
            totalContinueTime = paramList.get(1);
            totalS = totalSpeed * totalContinueTime;
        }
        SeacraftSouthSeaCurSpeedInfo curSpeedInfo = new SeacraftSouthSeaCurSpeedInfo();
        curSpeedInfo.setId(userInfo.getBaseData().getUserId());

        curSpeedInfo.setEndT(now + totalContinueTime);
        curSpeedInfo.setV(totalSpeed);
        shipData.getSpeedRecordList().add(curSpeedInfo);
        shipData.getSpeedRecordList().sort((t1, t2) -> {
            return Integer.compare(t1.getEndT(), t2.getEndT());
        });
        shipData.setUpdateOption();

        SeacraftSouthSeaUseSpeedUpInfo useSpeedUpInfo = userInfo.getBaseData().getUseSpeedUpInfoMap().get(propId);
        if (useSpeedUpInfo == null) {
            useSpeedUpInfo = new SeacraftSouthSeaUseSpeedUpInfo();
            useSpeedUpInfo.setPropId(propId);
            userInfo.getBaseData().getUseSpeedUpInfoMap().put(propId, useSpeedUpInfo);
        }
        useSpeedUpInfo.setNum(useSpeedUpInfo.getNum() + count);
        useSpeedUpInfo.setTotalValue(useSpeedUpInfo.getTotalValue() + totalS);
        userInfo.getBaseData().setUpdateOption();

        long currentTimeMs = DateHelper.getCurrentTime();
        addRecord(1, 5, userInfo.getBaseData().getUserId(), "", 0, 0, 0, count, currentTimeMs, propId, totalSpeed, totalContinueTime);
//        //  加日志
//        SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaDurable(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 5, userInfo.getBaseData().getUserId(), userInfo.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), currentTimeMs));

        // 广播船只信息
        activity.broadcastShipInfoToInActivityUser(this, null);
    }


    /**
     * 商会被发起道具攻击
     *
     * @param activity
     * @param attackUnion 攻击方所在的联盟
     * @param userInfo
     * @param count
     * @param titleId
     */
    public int propAttacked(SeacraftSouthSeaActivity activity, SeacraftSouthSeaUnionInfo attackUnion, SeacraftSouthSeaCrossUserInfo userInfo, int count, int titleId) {
        // 道具攻击
        int damage = 0;
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(userInfo.getBaseData().getActivityId());
        GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(activityConfig.getSEACRAFT_CRAFT_FIRE_ITEM_ID());
        long oldDurable = shipData.getRemainDurable();
        int oldSpeed = getShipSpeed();
        // 刷新进攻联盟的抵达时间
        int now = DateHelper.getCurrentSecond();
        refreshShip(activity, now);
        if (attackUnion.getShipData().getEndTime() <= 0 && shipData.getRemainDurable() > 0 && !isEnd(activity, false)) {
            // 攻击联盟未抵达，和 被攻击的船只耐久大于0  和被攻击船只未到达
            // 计算伤害
            damage = (goodsInfo.getParamList().get(0).intValue() + (titleId * goodsInfo.getParamList().get(1).intValue())) * count;
            damage = deductDurable(activity, damage);
        }
        // 积分=（参数1+参数2*身份等级）*参数3/1000
        int score = (goodsInfo.getParamList().get(0).intValue() + goodsInfo.getParamList().get(1).intValue() * titleId) * goodsInfo.getParamList().get(2).intValue() * count / 1000;
        long time = DateHelper.getCurrentTime();
        addRecord(1, 2, userInfo.getBaseData().getUserId(), "", 0, score, damage, 0, time, 0, 0, 0);
        attackUnion.addRecord(0, 2, userInfo.getBaseData().getUserId(), this.getUnionData().getUnionId(), 0, score, damage, 0, time, 0, 0, 0);

        // 加进攻 细节
        activity.addBattleDetail(attackUnion, userInfo.getBaseData().getUserId(), this, 2, damage, time);

        //  跑马灯
        if (damage > 0) {
            activity.broadcastSeacraftSouthSeaMarqueeInfo(userInfo.getBaseData().getUserId(), attackUnion, this, 2, 0, score, damage, 0, time);
        }
        // 日志
//        SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaDurable(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 6, userInfo.getBaseData().getUserId(), userInfo.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), time));
        CrossAutoLogMgr.add(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), 6, userInfo.getBaseData().getUserId(), userInfo.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), time));

        return score;
    }

    /**
     * 商会被发起攻击
     *
     * @param unionInfo    进攻方的商会
     * @param userInfo     攻击方
     * @param dispatchType 小队类型
     * @param attackType   进攻类型  0突袭 1进攻
     */
    public boolean attacked(SeacraftSouthSeaActivity activity, SeacraftSouthSeaUnionInfo unionInfo, SeacraftSouthSeaCrossUserInfo userInfo, int dispatchType, int attackType) {
        int rank = activity.getUnionRank(this, true);
        if (rank <= 0) {
            SeacraftSouthSeaMgr.getLogger().info("海上争霸 南海丝路 挑战船只获取对方排名数据异常。activityId:{},unionId:{},rank:{}", unionData.getActivityId(), unionData.getUnionId(), rank);
            return false;
        }
        // 成员攻击
        if (userInfo.getChallengeData() == null) {
            SeacraftSouthSeaCrossChallengeData challengeData = new SeacraftSouthSeaCrossChallengeData();
            challengeData.setActivityId(userInfo.getBaseData().getActivityId());
            challengeData.setUserId(userInfo.getBaseData().getUserId());
            challengeData.setInsertOption();
            userInfo.setChallengeData(challengeData);
        }
        userInfo.getChallengeData().setTargetId(unionData.getUnionId());
        userInfo.getChallengeData().setTeamType(dispatchType);
        userInfo.getChallengeData().setLockDurable(shipData.getRemainDurable());
        userInfo.getChallengeData().setAttackType(attackType);
        userInfo.getChallengeData().setTargetUnionRank(rank);
        long now = DateHelper.getCurrentTime();
        userInfo.getChallengeData().setDistance(unionInfo.getDistanceFromEnd(activity, now));
        userInfo.getChallengeData().setTargetDistance(getDistanceFromEnd(activity, now));
        // 随机出战成员
        randomTarget(userInfo);
        // 锁定门客数据
        SeacraftSouthSeaShipConfig shipConfig = SeacraftSouthSeaMgr.getShipConfig(unionInfo);

        userInfo.getChallengeData().getPatronsInfoList().clear();

        SeacraftSouthSeaTeamInfo teamInfo = userInfo.getBaseData().getShipMemberMap().get(dispatchType);

        long addPlus = SeacraftSouthSeaActivity.getTeamAddBuff(teamInfo);
        for (SeacraftSouthSeaPatronsInfo item : teamInfo.getTeamList()) {
            SeacraftSouthSeaLockPatronsInfo patronsInfo = copySeacraftSouthSeaPatronsInfo(item);
            // 计算血量 (天赋加成 船只加成)
            long initBlood = (item.getEarn() + shipConfig.getBonus()) * (1000 + addPlus) / 1000L;
            patronsInfo.setBlood(initBlood);
            patronsInfo.setMaxBlood(initBlood);
            userInfo.getChallengeData().getPatronsInfoList().add(patronsInfo);
        }
        if (attackType == 0) {
            // 突袭
            teamInfo.setRaidTimes(teamInfo.getRaidTimes() + 1);
            userInfo.getBaseData().setRaidAttackTimes(userInfo.getBaseData().getRaidAttackTimes() + 1);
        } else if (attackType == 1) {
            // 进攻
            teamInfo.setTimes(teamInfo.getTimes() + 1);
            userInfo.getBaseData().setUpdateOption();
        }
        return true;
    }

    private static SeacraftSouthSeaLockPatronsInfo copySeacraftSouthSeaPatronsInfo(SeacraftSouthSeaPatronsInfo item) {
        SeacraftSouthSeaLockPatronsInfo patronsInfo = new SeacraftSouthSeaLockPatronsInfo();
        patronsInfo.setId(item.getId());
        patronsInfo.setLv(item.getLv());
        patronsInfo.setStageLv(item.getStageLv());
        patronsInfo.setSkinId(item.getSkinId());
        patronsInfo.setEarn(item.getEarn());
        patronsInfo.setPromotionId(item.getPromotionId());
        patronsInfo.setAddPlus(item.getAddPlus());
        return patronsInfo;
    }

    /**
     * 距离终点的距离
     */
    private long getDistanceFromEnd(SeacraftSouthSeaActivity activity, long now) {
        CrossActivityDetail crossActivityDetail = ActivityMgr.getCrossActivityDetail(unionData.getActivityId(), activity.getGroupId(), true);
        if (crossActivityDetail.getParam1() <= 0) {
            return 0;
        }
        return activity.getRoundDistance() - getDistance(activity, (int) (crossActivityDetail.getParam1()), now);
    }


    /**
     * 随机船员接受挑战
     */
    private void randomTarget(SeacraftSouthSeaCrossUserInfo userInfo) {
        if (userInfo.getChallengeData().getAttackedList().size() >= memberMap.size()) {
            // 全部打完
            return;
        }
        userInfo.getChallengeData().getRandomMap().clear();
        List<SeacraftSouthSeaCrossUserInfo> memberList = new ArrayList<>(memberMap.values());
        Collections.shuffle(memberList);
        memberList.forEach(e -> {
            if (userInfo.getChallengeData().getRandomMap().size() >= 3) {
                return;
            }
            if (!userInfo.getChallengeData().getAttackedList().contains(e.getBaseData().getUserId())) {
                // 随机 对方的小队类型
                List<Integer> teamTypeList = new ArrayList<>(e.getBaseData().getShipMemberMap().keySet());
                if (teamTypeList.size() > 0) {
                    Collections.shuffle(teamTypeList);
                    userInfo.getChallengeData().getRandomMap().put(e.getBaseData().getUserId(), teamTypeList.get(0));
                }
            }
        });
    }


    /**
     * 商会成员被挑战
     *
     * @param activityInfo
     * @param attacker     挑战者
     * @param memberId     被挑战联盟成员id
     * @param type         挑战类型
     * @return
     */
    public SeacraftSouthSeaProto.SeacraftSouthSeaChallengeRespMsg.Builder challenged(SeacraftSouthSeaActivity activityInfo, SeacraftSouthSeaCrossUserInfo attacker, long memberId, int type, int blood, int buffId, long goldNum) {
        SeacraftSouthSeaProto.SeacraftSouthSeaChallengeRespMsg.Builder builder = SeacraftSouthSeaProto.SeacraftSouthSeaChallengeRespMsg.newBuilder();
        boolean isWin = false;
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(activityInfo.getActivityId());
        if (type == 2) {
            if (buffId <= 0 || buffId > activityConfig.buyCostList.size()) {
                builder.setRet(GameErrorCode.E_SEACRAFT_SOUTH_SEA_ACTIVITY_BUFF_NO_EXIST);
                return builder;
            }
            // 一键挑战
            if (attacker.getBaseData().getAttackNum() < activityConfig.getSEACRAFT_CRAFT_QUICKFIGHT_LIMIT_NUM()) {
                builder.setRet(GameErrorCode.E_SEACRAFT_SOUTH_SEA_ACTIVITY_ONE_KEY_FIGHT_NO_LOCK);
                return builder;
            }
            int consumeGoldNum = 0;
            while (attacker.getChallengeData().getRandomMap().size() > 0) {
                Map<Long, Integer> tempMap = new HashMap<>(attacker.getChallengeData().getRandomMap());
                for (Map.Entry<Long, Integer> entry : tempMap.entrySet()) {
                    // 判断是否购买buff
                    int buyBuffId = 0;
                    List<Integer> addBloodPatronsList = new ArrayList<>();
                    if (attacker.getChallengeData().getBuyBuffId() == 0 && attacker.getChallengeData().getWinStreakNum() != 0 && buffId != 0 && blood <= 100) {
                        long totalBlood = activityInfo.getTotalBlood(attacker);
                        long remainBlood = activityInfo.getRemainBlood(attacker);
                        if ((remainBlood * 100 / totalBlood) < blood) {
                            // 判断是否低于该血量
                            int needNum = activityConfig.buyCostList.get(buffId - 1);
                            if (consumeGoldNum + needNum <= goldNum) {
                                int addValue = activityConfig.addBuffList.get(buffId - 1);
                                addBloodPatronsList.addAll(activityInfo.addBuffToTeam(attacker, buffId, addValue));
                                consumeGoldNum += needNum;
                                buyBuffId = buffId;
                            }
                        }
                    }
                    SeacraftSouthSeaCrossUserInfo targetUser = memberMap.get(entry.getKey());
                    if (targetUser == null) {
                        // 加个保护
                        continue;
                    }
                    SeacraftSouthSeaTeamInfo targetTeamInfo = targetUser.getBaseData().getShipMemberMap().get(entry.getValue());
                    SeacraftSouthSeaProto.SeacraftSouthSeaBattleDetail.Builder result = battle(activityInfo, attacker, entry.getKey(), targetTeamInfo, true);
                    result.setBuyBuffId(buyBuffId);
                    result.addAllAddBloodPatronsList(addBloodPatronsList);
                    isWin = result.getIsWin();
                    if (isWin) {
                        // 判断是否可以领取连胜奖励
                        if (activityInfo.canRecWinStreakReward(attacker)) {
                            // 领取的连胜奖励
                            int rewardType = attacker.getChallengeData().getAttackType() == 0 ? 1 : 2;
                            int boxId = activityConfig.getWinStreakReward(this.unionData.getRound(), rewardType, attacker.getChallengeData().getTargetUnionRank(), attacker.getChallengeData().getWinStreakNum());
                            if (boxId != 0) {
                                // 领取奖励
                                OpenGoodsBagResult openResult = TempGoodsBagMgr.getRandomGoods(boxId);
                                result.setWinStreakReward(PropertyHelper.parsePropertyToString(openResult.getReward()));
                                attacker.getChallengeData().setReceiveWinStreakTimes(attacker.getChallengeData().getWinStreakNum());
                                attacker.getChallengeData().getWinStreakReward().addProperty(openResult.getReward());
                            }
                        }
                    }
                    builder.addBattleDetailList(result);
                    if (!isWin) {
                        break;
                    }
                }
                if (!isWin) {
                    break;
                }
                //  随机新的船员
                randomTarget(attacker);
            }
            builder.setConsumeGoldNum(consumeGoldNum);
        } else {
            SeacraftSouthSeaCrossUserInfo targetUser = memberMap.get(memberId);
            if (targetUser == null) {
                builder.setRet(GameErrorCode.E_SEACRAFT_SOUTH_SEA_ACTIVITY_CHALLENGE_USER_NO_EXIST);
                return builder;
            }
            // 单次
            Integer teamType = attacker.getChallengeData().getRandomMap().get(memberId);
            if (teamType == null) {
                builder.setRet(GameErrorCode.E_SEACRAFT_SOUTH_SEA_ACTIVITY_CHALLENGE_USER_NO_EXIST);
                return builder;
            }
            // 目标队伍
            SeacraftSouthSeaTeamInfo targetTeamInfo = targetUser.getBaseData().getShipMemberMap().get(teamType);
            SeacraftSouthSeaProto.SeacraftSouthSeaBattleDetail.Builder result = battle(activityInfo, attacker, targetUser.getBaseData().getUserId(), targetTeamInfo, false);
            isWin = result.getIsWin();
            if (isWin) {
                //  随机新的船员
                randomTarget(attacker);
            }
            builder.addBattleDetailList(result);
        }
        // 是否结算
        boolean isKillAll = activityInfo.isKillAll(attacker, this);
        if (!isWin || isKillAll) {
            // 战斗日志
            String reward = null;
            if (isKillAll) {
                reward = activityConfig.battleRewardList.get(0);
            } else {
                reward = activityConfig.battleRewardList.get(1);
            }
            int medalNum = activityInfo.getMedalNum(activityConfig, attacker);
            //SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaAttack(new LogSeacraftSouthSeaAttack(unionData.getActivityId(), attacker.getBaseData().getUnionId(), attacker.getChallengeData().getDistance(), attacker.getBaseData().getUserId(), attacker.getChallengeData().getTeamType(), attacker.getChallengeData().getAttackType(), attacker.getChallengeData().getTargetId(), attacker.getChallengeData().getTargetDistance(), attacker.getChallengeData().getKillPatronsNum(), attacker.getChallengeData().getWinStreakNum(), isKillAll, reward, medalNum, DateHelper.getCurrentTime()));
            CrossAutoLogMgr.add(new LogSeacraftSouthSeaAttack(unionData.getActivityId(), attacker.getBaseData().getUnionId(), attacker.getChallengeData().getDistance(), attacker.getBaseData().getUserId(), attacker.getChallengeData().getTeamType(), attacker.getChallengeData().getAttackType(), attacker.getChallengeData().getTargetId(), attacker.getChallengeData().getTargetDistance(), attacker.getChallengeData().getKillPatronsNum(), attacker.getChallengeData().getWinStreakNum(), isKillAll, reward, medalNum, DateHelper.getCurrentTime()));
        }
        SeacraftSouthSeaProto.SeacraftSouthSeaChallengeResult.Builder challengeResult = activityInfo.settlement(attacker, !isWin);
        if (challengeResult != null) {
            builder.setResult(challengeResult);
        }
        builder.setChallengeInfo(activityInfo.builderSeacraftSouthSeaChallengeInfo(attacker));
        builder.setRank(activityInfo.getUserRank(attacker.getBaseData().getUserId()));
        builder.setAllScore(activityInfo.getUserScore(attacker.getBaseData().getUserId()));
        builder.setRet(0);
        return builder;
    }


    /**
     * 小队pk
     *
     * @param attacker
     * @param defenderId
     * @param defendTeam 防守队伍
     * @return
     */
    private SeacraftSouthSeaProto.SeacraftSouthSeaBattleDetail.Builder battle(SeacraftSouthSeaActivity activityInfo, SeacraftSouthSeaCrossUserInfo attacker, long defenderId, SeacraftSouthSeaTeamInfo defendTeam, boolean oneKey) {
        SeacraftSouthSeaProto.SeacraftSouthSeaBattleDetail.Builder result = SeacraftSouthSeaProto.SeacraftSouthSeaBattleDetail.newBuilder();
        // 日志用 进攻前的血量 门客id=血量;...
        Integer teamType = attacker.getChallengeData().getRandomMap().get(defenderId);
        Map<Integer, SeacraftSouthSeaPatronsInfo> defendMap = new HashMap<>();
        Map<Integer, SeacraftSouthSeaLockPatronsInfo> attackMap = new HashMap<>();
        List attackList = new ArrayList<>();
        List defendList = new ArrayList<>();
        long oldBlood = activityInfo.getTeamBlood(attacker);
        for (SeacraftSouthSeaLockPatronsInfo item : attacker.getChallengeData().getPatronsInfoList()) {
            if (item.getBlood() > 0) {
                SeacraftSouthSeaPatronsInfo patronsInfo = new SeacraftSouthSeaPatronsInfo();
                patronsInfo.setId(item.getId());
                patronsInfo.setEarn(item.getBlood());
                attackList.add(patronsInfo);
                attackMap.put(item.getId(), item);
            }
        }
        int defendBuffValue = 0;
        for (SeacraftSouthSeaPatronsInfo item : defendTeam.getTeamList()) {
            SeacraftSouthSeaPatronsInfo patronsInfo = new SeacraftSouthSeaPatronsInfo();
            patronsInfo.setId(item.getId());
            patronsInfo.setEarn(item.getEarn());
            defendList.add(patronsInfo);
            defendMap.put(patronsInfo.getId(), patronsInfo);
            defendBuffValue += item.getAddPlus();
        }

        String attackBeforeBloodInfo = getPatronsBloodStr(attacker.getChallengeData().getPatronsInfoList());
        String targetBeforeBloodInfo = getPatronsBloodStr(defendTeam.getTeamList());
        // 进攻方门客数据
        result.addAllAttackPatronsList(SeacraftSouthSeaActivity.builderSeacraftSouthSeaPatronsInfoList(attacker));
        BattleResult battleResult = BattleMgr.battle(defenderId, defendList, defendBuffValue, attacker.getBaseData().getUserId(), attackList, 0);
        // 扣血量
        for (PatronsBattleDetail detail : battleResult.getPatronsBattleDetailList()) {
            attackMap.get(detail.getMyPatronsId()).setBlood(Math.max(0, detail.getMyPatronsCurrentBlood().longValue()));
            defendMap.get(detail.getEnemyPatronsId()).setEarn(Math.max(0, detail.getEnemyPatronsCurrentBlood().longValue()));
        }

        int oldSpeed = getShipSpeed();
        long oldDurable = shipData.getRemainDurable();

        boolean isWin = battleResult.getWinUserId() == attacker.getBaseData().getUserId();
        for (SeacraftSouthSeaPatronsInfo item : defendTeam.getTeamList()) {
            SeacraftSouthSeaProto.SeacraftSouthSeaPatronsEntity.Builder patronsEntity = SeacraftSouthSeaProto.SeacraftSouthSeaPatronsEntity.newBuilder();
            patronsEntity.setPatronsId(item.getId());
            patronsEntity.setLevel(item.getLv());
            patronsEntity.setStageLv(item.getStageLv());
            patronsEntity.setSkinId(item.getSkinId());
            patronsEntity.setEarn(item.getEarn());
            patronsEntity.setAddPlus(item.getAddPlus());
            patronsEntity.setPromotionId(item.getPromotionId());
            result.addEnemyPatronsList(patronsEntity);
        }
        long newBlood = activityInfo.getTeamBlood(attacker);
        result.setDamage(oldBlood - newBlood);
        result.setTeamBlood(newBlood);
        result.setBattleDetailList(BattlePb.parseBattleDetailListMsg(battleResult.getPatronsBattleDetailList()));
        result.setIsWin(isWin);
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());

        int score = battleResult.getKillPatronsCount() * activityConfig.killPointList.get(0);
        int durable = battleResult.getKillPatronsCount() * activityConfig.killPointList.get(1);

        result.setScore(score);
        result.setKillPatronsNum(battleResult.getKillPatronsCount());
        // 战斗完成
        // 加积分
        attacker.getBaseData().setScore(attacker.getBaseData().getScore() + score);
        // 船只扣耐久
        SeacraftSouthSeaUnionInfo attackUnion = activityInfo.getUnionInfo(attacker.getBaseData().getUnionId(), true);
        //
        long now = DateHelper.getCurrentTime();
        attackUnion.refreshShip(activityInfo, now);
        refreshShip(activityInfo, now);
        int realDurable = 0;
        if (attackUnion.getShipData().getEndTime() <= 0 && shipData.getRemainDurable() > 0 && !isEnd(activityInfo, false)) {
            refreshShip(activityInfo, now);
            // 攻击方的船只未到达
            realDurable = deductDurable(activityInfo, durable);
        }
        result.setDurable(realDurable);
        if (isWin) {
            // 挑战成功
            attacker.getChallengeData().setWinStreakNum(attacker.getChallengeData().getWinStreakNum() + 1);
            attacker.getChallengeData().getAttackedList().add(defenderId);
        }
        // 日志用
        int buyBuffValue = 0;
        if (attacker.getChallengeData().getBuyBuffId() > 0) {
            buyBuffValue = attacker.getChallengeData().getBuffValueList().get(attacker.getChallengeData().getBuffValueList().size() - 1);
        }

        attacker.getChallengeData().setBuyBuffId(0);
        attacker.getChallengeData().getRandomMap().remove(defenderId);
        attacker.getChallengeData().setDeductDurable(attacker.getChallengeData().getDeductDurable() + realDurable);
        attacker.getChallengeData().setTotalScore(attacker.getChallengeData().getTotalScore() + result.getScore());
        attacker.getChallengeData().setKillPatronsNum(attacker.getChallengeData().getKillPatronsNum() + battleResult.getKillPatronsCount());
        // 船只耐久变更日志
        int type = 0;
        if (attacker.getChallengeData().getAttackType() == 1) {
            type = 3;
        } else {
            type = 4;
        }
        // 耐久日志
//        SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaDurable(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), type, attacker.getBaseData().getUserId(), attacker.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), now));
        CrossAutoLogMgr.add(new LogSeacraftSouthSeaDurable(unionData.getActivityId(), unionData.getUnionId(), type, attacker.getBaseData().getUserId(), attacker.getBaseData().getUnionId(), oldDurable, oldSpeed, shipData.getRemainDurable(), getShipSpeed(), now));
        // 加战斗流水日志
        // 日志用 进攻前的血量 门客id=血量;...
        String attackAfterBloodInfo = getPatronsBloodStr(attacker.getChallengeData().getPatronsInfoList());
        String targetAfterBloodInfo = getPatronsBloodStr(defendList);

//        SeacraftSouthSeaLogMgr.addLogSeacraftSouthSeaAttackDetail(new LogSeacraftSouthSeaAttackDetail(unionData.getActivityId(), attacker.getBaseData().getUnionId(), attacker.getBaseData().getUserId(), attacker.getChallengeData().getTeamType(), attacker.getChallengeData().getAttackType(), oneKey, buyBuffValue, StringUtils.listToString(attacker.getChallengeData().getBuffValueList(), ","), attackBeforeBloodInfo, attackAfterBloodInfo, attacker.getChallengeData().getTargetId(), defenderId, teamType, targetBeforeBloodInfo, targetAfterBloodInfo, attacker.getChallengeData().getKillPatronsNum(), isWin, attacker.getChallengeData().getWinStreakNum()));
        CrossAutoLogMgr.add(new LogSeacraftSouthSeaAttackDetail(unionData.getActivityId(), attacker.getBaseData().getUnionId(), attacker.getBaseData().getUserId(), attacker.getChallengeData().getTeamType(), attacker.getChallengeData().getAttackType(), oneKey, buyBuffValue, StringUtils.listToString(attacker.getChallengeData().getBuffValueList(), ","), attackBeforeBloodInfo, attackAfterBloodInfo, attacker.getChallengeData().getTargetId(), defenderId, teamType, targetBeforeBloodInfo, targetAfterBloodInfo, attacker.getChallengeData().getKillPatronsNum(), isWin, attacker.getChallengeData().getWinStreakNum()));

        UserBaseInfo defendUserInfo = CrossUserMgr.getUserBaseInfo(defenderId);
        if (defendUserInfo != null) {
            result.setTargetServerId(defendUserInfo.getServerId());
            result.setTargetUserName(defendUserInfo.getNickName());
        }
        return result;
    }

    /**
     * 加联盟日志
     *
     * @param masterType  日志类型 （0攻击 1防守）
     * @param sonType     子类型 0突袭 1进攻 2 道具进攻 3道具修复 5使用加速道具
     * @param userId
     * @param targetId    目标商会id 当masterType = 0 ，sonType =012 5 才有
     * @param killNum
     * @param score
     * @param durable
     * @param goodsUseNum
     * @param time        ms
     */
    public void addRecord(int masterType, int sonType, long userId, String targetId, int killNum, int score, int durable, int goodsUseNum, long time, int propId, int speed, int continueTime) {
        SeacraftSouthSeaCrossRecordData recordData = new SeacraftSouthSeaCrossRecordData();
        recordData.setActivityId(unionData.getActivityId());
        recordData.setUnionId(unionData.getUnionId());
        recordData.setMasterType(masterType);
        recordData.setSonType(sonType);
        recordData.setUserId(userId);
        recordData.setTargetId(targetId);
        recordData.setKillNum(killNum);
        recordData.setScore(score);
        recordData.setDurable(durable);
        recordData.setGoodsUseNum(goodsUseNum);
        recordData.setTime(time);
        recordData.setPropId(propId);
        recordData.setSpeed(speed);
        recordData.setContinueTime(continueTime);
        recordData.setInsertOption();
        addRecord(recordData);
    }

    private String getPatronsBloodStr(List list) {
        StringBuilder str = new StringBuilder();
        for (Object item : list) {
            IBattleObjectInfo e = (IBattleObjectInfo) item;
            long blood = e.getValue() < 0 ? 0 : e.getValue();
            str.append(e.getObjectId()).append("=").append(blood).append("|");
        }

        return str.substring(0, str.length() - 1);
    }

    public void addRecord(SeacraftSouthSeaCrossRecordData item) {
        if (item.getMasterType() == 0) {
            // 攻击
            while (attackRecordList.size() >= 100) {
                attackRecordList.remove(0);
            }
            attackRecordList.add(item);
        } else if (item.getMasterType() == 1) {
            // 防守
            while (defendRecordList.size() >= 100) {
                defendRecordList.remove(0);
            }
            defendRecordList.add(item);
        }
    }

    /**
     * 获取该轮行驶的距离
     */
    public long getDistance(SeacraftSouthSeaActivity activity, int round, long now) {
        if (unionData.getRound() != round) {
            // 该联盟未晋级到该轮
            return 0;
        }
        // 该轮开始时间
        long roundStartTime = SeacraftSouthSeaMgr.getRoundStartTime(unionData.getActivityId(), round);
        if (now < roundStartTime || roundStartTime == 0) {
            // 比赛还未开始
            return 0;
        }
        if (shipData == null) {
            return 0;
        }
        refreshShip(activity, now);
        return shipData.getDistance();
    }


    /**
     * 是否到达终点
     *
     * @return
     */
    public boolean isEnd(SeacraftSouthSeaActivity activity, boolean refresh) {
        if (shipData.getEndTime() > 0) {
            return true;
        }
        long now = DateHelper.getCurrentTime();
        if (refresh) {
            refreshShip(activity, now);
        }
        long distance = getDistance(activity, unionData.getRound(), now);
        if (distance >= activity.getRoundDistance()) {
            return true;
        }
        return false;
    }

    /**
     * 船只是否损坏
     *
     * @return
     */
    public boolean isDamage() {
        if (shipData != null) {
            return shipData.getRemainDurable() <= 0;
        }
        return false;
    }


    public void setShipData(SeacraftSouthSeaCrossUnionShipData shipData) {
        this.shipData = shipData;
    }

    public SeacraftSouthSeaProto.SeacraftSouthSeaShipInfo.Builder builderSeacraftSouthSeaShipInfo() {
        SeacraftSouthSeaProto.SeacraftSouthSeaShipInfo.Builder builder = SeacraftSouthSeaProto.SeacraftSouthSeaShipInfo.newBuilder();
        builder.setUnionId(unionData.getUnionId());
        builder.setUnionName(unionData.getUnionBaseInfo().getUnionName());
        builder.setServerId(unionData.getUnionBaseInfo().getServerId());
        builder.setLevel(SeacraftSouthSeaMgr.getShipConfig(this).getLevel());
        builder.setTotalDurable(shipData.getTotalDurable());
        builder.setRemainDurable(shipData.getRemainDurable());
        builder.setDistance(shipData.getDistance());
        builder.setV(getShipSpeed());
        builder.setTime(shipData.getEndTime());
        builder.setRefreshTime(shipData.getRefreshTime());
        builder.setNo(unionData.getRank());
        builder.setFixRefreshTime(shipData.getFixRefreshTime());
        for (SeacraftSouthSeaCurSpeedInfo item : getSpeedRecordList()) {
            SeacraftSouthSeaProto.SeacraftSouthSeaSpeedUpSimpleInfo.Builder speedUpSimpleInfo = SeacraftSouthSeaProto.SeacraftSouthSeaSpeedUpSimpleInfo.newBuilder();
            speedUpSimpleInfo.setSpeed(item.getV());
            speedUpSimpleInfo.setEndTime(item.getEndT());
            builder.addCurSpeedInfoList(speedUpSimpleInfo.build());
        }
        return builder;
    }

    public List<SeacraftSouthSeaCurSpeedInfo> getSpeedRecordList() {
        List<SeacraftSouthSeaCurSpeedInfo> list = new ArrayList<>();
        // s
        int now = DateHelper.getCurrentSecond();
        for (SeacraftSouthSeaCurSpeedInfo item : shipData.getSpeedRecordList()) {
            if (item.getEndT() <= now) {
                continue;
            }
            list.add(item);
        }
        return list;
    }


//    /**
//     * 计算船只预计到达时间
//     *
//     * @return
//     */
//    public long getShipPredictArriveTime(SeacraftSouthSeaActivity southSeaActivity) {
//        CrossActivityDetail crossActivityDetail = ActivityMgr.getCrossActivityDetail(unionData.getActivityId(), true);
//        if (shipData == null) {
//            // 没有船只
//            return 0;
//        }
//        if (unionData.getRound() != crossActivityDetail.getParam1()) {
//            // 未晋级
//            return 0;
//        }
//        long now = DateHelper.getCurrentTime();
//        long roundStartTime = SeacraftSouthSeaMgr.getRoundStartTime(unionData.getActivityId(), unionData.getRound());
//        if (now < roundStartTime) {
//            // 比赛还未开始
//            return 0;
//        }
//        if (shipData.getEndTime() > 0) {
//            // 已经到达
//            return shipData.getEndTime();
//        }
//        SeacraftSouthSeaActivityConfig seaActivityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());
//        if (seaActivityConfig == null) {
//            // 缺少活动配置
//            return 0;
//        }
//        long roundEndTime = SeacraftSouthSeaMgr.getRoundEndTime(unionData.getActivityId(), unionData.getRound());
//
//        // 计算预计到达时间
//        long distance = getDistance(southSeaActivity, unionData.getRound(), now);
//        long remainDistance = southSeaActivity.getRoundDistance() - distance;
//        if (remainDistance <= 0) {
//            refreshShip(southSeaActivity, now);
//            return shipData.getEndTime();
//        }
//        // 当前速度 speed 放大100 倍
//        int speed = getShipSpeed();
//        // 需要的时间
//        if (speed <= 0) {
//            return roundEndTime;
//        }
//        long time = remainDistance * 100 * 1000 / speed;
//        long predictArriveTime = now + time;
//        return Math.min(predictArriveTime, roundEndTime);
//    }

    /**
     * 查看船只攻防信息
     *
     * @param type
     */
    public List<SeacraftSouthSeaProto.SeacraftSouthSeaBattleRecordInfo> getBattleRecord(SeacraftSouthSeaActivity activity, int type) {
        List<SeacraftSouthSeaProto.SeacraftSouthSeaBattleRecordInfo> list = new ArrayList<>();
        Map<String, SeacraftSouthSeaBattleDetailData> tempAttackBattleMap = null;
        if (type == 0) {
            tempAttackBattleMap = attackBattleMap;
        } else {
            tempAttackBattleMap = defendBattleMap;
        }
        for (SeacraftSouthSeaBattleDetailData item : tempAttackBattleMap.values()) {
            list.add(activity.builderSeacraftSouthSeaBattleRecordInfo(item).build());
        }
        return list;
    }

    /**
     * 查看船只成员详细攻防数据
     *
     * @return
     */
    public List<SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo> getMemberBattleDetail(SeacraftSouthSeaActivity activity, int type, int sonType, String targetId) {
        List<SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo> list = new ArrayList<>();
        Map<String, SeacraftSouthSeaBattleDetailData> tempAttackBattleMap = null;
        if (type == 0) {
            tempAttackBattleMap = attackBattleMap;
        } else {
            tempAttackBattleMap = defendBattleMap;
        }
        SeacraftSouthSeaBattleDetailData detailData = tempAttackBattleMap.get(targetId);
        if (detailData != null) {
            if (sonType == 0) {
                Map<Long, SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo.Builder> map = new HashMap<>();
                setSeacraftSouthSeaMemberBattleDetailInfoMap(map, detailData.getRaidAttackMap());
                setSeacraftSouthSeaMemberBattleDetailInfoMap(map, detailData.getAttackMap());
                setSeacraftSouthSeaMemberBattleDetailInfoMap(map, detailData.getUseGoodMap());
                for (SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo.Builder item : map.values()) {
                    if (item.getValue() > 0) {
                        list.add(item.build());
                    }
                }
            } else if (sonType == 1) {
                list = activity.builderSeacraftSouthSeaMemberBattleDetailInfoList(detailData.getRaidAttackMap());
            } else if (sonType == 2) {
                list = activity.builderSeacraftSouthSeaMemberBattleDetailInfoList(detailData.getAttackMap());
            } else if (sonType == 3) {
                list = activity.builderSeacraftSouthSeaMemberBattleDetailInfoList(detailData.getUseGoodMap());
            }
        }
        return list;
    }

    private void setSeacraftSouthSeaMemberBattleDetailInfoMap(Map<Long, SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo.Builder> map, Map<Long, SeacraftSouthSeaBattleDetailInfo> attackMap) {
        if (attackMap != null) {
            for (Map.Entry<Long, SeacraftSouthSeaBattleDetailInfo> entry : attackMap.entrySet()) {
                SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo.Builder builder = map.get(entry.getKey());
                if (builder == null) {
                    builder = SeacraftSouthSeaProto.SeacraftSouthSeaMemberBattleDetailInfo.newBuilder();
                    builder.setUserName(CrossUserMgr.getUserName(entry.getKey()));
                    builder.setServerId(CrossUserMgr.getServerIdByUserId(entry.getKey()));
                    map.put(entry.getKey(), builder);
                }
                builder.setValue(builder.getValue() + entry.getValue().getV());
                builder.setTime(Math.max(entry.getValue().getT(), builder.getTime()));
            }
        }
    }

    /**
     * @param masterType
     * @param sonType    0突袭 1进攻 2 道具进攻 3道具修复
     * @param targetId
     */
    public void addBattleDetail(int masterType, int sonType, String targetId, long userId, long durable, long time) {
        SeacraftSouthSeaBattleDetailData battleDetailData = null;
        if (masterType == 0) {
            battleDetailData = attackBattleMap.get(targetId);
            if (battleDetailData == null) {
                battleDetailData = new SeacraftSouthSeaBattleDetailData();
                battleDetailData.setActivityId(unionData.getActivityId());
                battleDetailData.setUnionId(unionData.getUnionId());
                battleDetailData.setTargetUnionId(targetId);
                battleDetailData.setMasterType(masterType);
                battleDetailData.setRound(this.unionData.getRound());
                battleDetailData.setInsertOption();
                attackBattleMap.put(targetId, battleDetailData);
            }
        } else if (masterType == 1) {
            battleDetailData = defendBattleMap.get(targetId);
            if (battleDetailData == null) {
                battleDetailData = new SeacraftSouthSeaBattleDetailData();
                battleDetailData.setActivityId(unionData.getActivityId());
                battleDetailData.setUnionId(unionData.getUnionId());
                battleDetailData.setTargetUnionId(targetId);
                battleDetailData.setMasterType(masterType);
                battleDetailData.setRound(this.unionData.getRound());
                battleDetailData.setInsertOption();
                defendBattleMap.put(targetId, battleDetailData);
            }
        }
        if (battleDetailData != null) {
            battleDetailData.setActivityId(unionData.getActivityId());
            battleDetailData.setUnionId(unionData.getUnionId());
            battleDetailData.setTargetUnionId(targetId);
            battleDetailData.setMasterType(masterType);
            battleDetailData.setTime(time);
            SeacraftSouthSeaBattleDetailInfo seaBattleDetailInfo = null;
            int recordTime = (int) (time / 1000);
            if (sonType == 0) {
                seaBattleDetailInfo = battleDetailData.getRaidAttackMap().get(userId);
                if (seaBattleDetailInfo == null) {
                    seaBattleDetailInfo = new SeacraftSouthSeaBattleDetailInfo();
                    seaBattleDetailInfo.setT(recordTime);
                    battleDetailData.getRaidAttackMap().put(userId, seaBattleDetailInfo);
                }
            } else if (sonType == 1) {
                seaBattleDetailInfo = battleDetailData.getAttackMap().get(userId);
                if (seaBattleDetailInfo == null) {
                    seaBattleDetailInfo = new SeacraftSouthSeaBattleDetailInfo();
                    seaBattleDetailInfo.setT(recordTime);
                    battleDetailData.getAttackMap().put(userId, seaBattleDetailInfo);
                }
            } else if (sonType == 2) {
                seaBattleDetailInfo = battleDetailData.getUseGoodMap().get(userId);
                if (seaBattleDetailInfo == null) {
                    seaBattleDetailInfo = new SeacraftSouthSeaBattleDetailInfo();
                    seaBattleDetailInfo.setT(recordTime);
                    battleDetailData.getUseGoodMap().put(userId, seaBattleDetailInfo);
                }
            }
            if (seaBattleDetailInfo != null) {
                seaBattleDetailInfo.setV(seaBattleDetailInfo.getV() + durable);
            }
            battleDetailData.setUpdateOption();
        }
    }

    /**
     * 最大使用修复道具的数量
     *
     * @param titleId
     * @return
     */
    public int canUseFixGoodMaxNum(int titleId) {
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());
        if (activityConfig != null) {
            GoodsInfo goodsInfo = GoodsMgr.getGoodsInfo(activityConfig.getSEACRAFT_CRAFT_WRENCH_ITEM_ID());
            int damage = goodsInfo.getParamList().get(0).intValue() + (titleId * goodsInfo.getParamList().get(1).intValue());
            return (int) (((shipData.getTotalDurable() - shipData.getRemainDurable()) + damage - 1) / damage);
        }
        return 0;
    }

    /**
     * 刷新船只修理
     *
     * @param now ms
     */
    public void refreshFixShip(long now) {
        if (shipData.getTotalDurable() <= shipData.getRemainDurable()) {
            shipData.setFixRefreshTime(now);
            return;
        }
        SeacraftSouthSeaActivityConfig activityConfig = SeacraftSouthSeaConfigMgr.getConfigMap().get(unionData.getActivityId());
        if (activityConfig != null) {
            long diffTime = (now - shipData.getFixRefreshTime()) / DateHelper.SECOND_MILLIONS;
            int cd = activityConfig.getRepairParam().get(1);
            long times = diffTime / cd;
            if (times > 0) {
                long addDurable = (activityConfig.getRepairParam().get(0) * shipData.getTotalDurable() / 1000) * times;
                addDurable(addDurable);
                shipData.setFixRefreshTime(shipData.getFixRefreshTime() + times * cd * DateHelper.SECOND_MILLIONS);
            }
        }
    }


}
